#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
Simplified BSD License (BSD)
Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this 
      list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#region Record of Change
//             							CHANGE HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | DEVELOPER  | DESCRIPTION                                              |
// -------------------------------------------------------------------------------------
// | 01-Nov-09 | HaiNM      | First creation.                                          |
// -------------------------------------------------------------------------------------
//
#endregion

#region Record of Audit
//             							REVIEW HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | REVIEWER   | NOTES                                                    |
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
//
#endregion

#region Using directives
using System;
using System.Drawing;
using System.Drawing.Text;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.ComponentModel;

using Thn;
using Thn.Interface.Vcl.Themes;
#endregion

namespace Thn.Interface.Vcl
{
    /// <summary>
    /// Base class for visual controls.
    /// </summary>
    /// <remarks>This class supports transparency by double-buffering and by capturing all underlying
    /// controls' images.</remarks>
#if DEBUG
    public
#else
    public
#endif
 class ControlBase : UserControl
                            , IControl
                            , ISupportTransparency
                            , ISupportTheme
                            , IMouseListener
                            , IKeyboardListener
    {
        #region Fields
        /// <summary>
        /// Method of achieving transparency.
        /// </summary>
        protected TransparencyMethod mTransparencyMethod = TransparencyMethod.ForcedPainting;

        /// <summary>
        /// Whether method OnPaint should return immediately without painting.
        /// </summary>
        protected bool mSkipPaint = false;
        /// <summary>
        /// Get background image again (for transparency effect)
        /// </summary>
        protected bool mRedrawBackground = true;

        /// <summary>
        /// Whether this control needs to be rendered again.
        /// </summary>
        protected bool mRenderRequired = true;
        /// <summary>
        /// Whether this controls needs to be
        /// </summary>
        protected bool mRecalculateLayout = true;
        #endregion

        #region Properties

        #region Design Mode
        bool mDesignMode = false;
        /// <summary>
        /// Checks whether this control is in design mode.
        /// <para>
        /// Note: this property is assigned via Thn.Interface.Vcl.UI.DesignMode
        /// </para>
        /// </summary>
        public new bool DesignMode
        {
            //get { return UI.DesignMode; }
            get { return mDesignMode; }
        }
        #endregion

        #region Transparent
        private bool mTransparent;
        /// <summary>
        /// Gets/Sets whether this control can show its parent's painting.
        /// </summary>
        [Browsable(true), DefaultValue(false), Category("Appearance"), Description("Whether this control can show its parent's painting")]
        public bool Transparent
        {
            get { return mTransparent; }
            set
            {
                mTransparent = value;
                if (mTransparencyMethod == TransparencyMethod.TransparentWindows)
                {
                    //hack for proper transparency
                    this.BackColor = Color.Transparent;
                }
                #region Defensive tracing
                else
                {
                    //no need to hack color if not Transparent Windows method
                }
                #endregion

                RecreateHandle();
                Invalidate();
            }
        }
        #endregion

        #region Cache Background
        /// <summary>
        /// Whether this control should cache its background for faster transparency painting.
        /// </summary>
        protected bool mCacheBackground = true;
        /// <summary>
        /// Gets/Sets whether this control should cache its background for faster transparency painting.
        /// </summary>
        [Browsable(true), DefaultValue(true), Category("Appearance"), Description("Save background for faster transparency painting.")]
        public bool CacheBackground
        {
            get { return mCacheBackground; }
            set
            {
                mCacheBackground = value;
                Invalidate();
            }
        }
        #endregion

        #region Quality
        private RenderQuality mQuality = RenderQuality.Normal;
        /// <summary>
        /// Gets/Sets the renderation quality.
        /// </summary>
        [Browsable(true), DefaultValue(RenderQuality.Normal), Category("Appearance"), Description("Quality of renderation")]
        public RenderQuality Quality
        {
            get { return mQuality; }
            set
            {
                mQuality = value;
                Invalidate();
            }
        }
        #endregion

        #region Text
        private string mText = "";
        /// <summary>
        /// Gets/Sets the display text.
        /// </summary>
        [Browsable(true), DefaultValue(""), Category("Value"), Description("Displayed text"), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string Text
        {
            get
            {
                return mText;
            }
            set
            {
                if (mText != value)
                {
                    mText = value;
                    Invalidate();
                    OnTextChanged(EventArgs.Empty);
                }
            }
        }
        #endregion

        #region Theme
        private string mTheme = "";
        /// <summary>
        /// Gets/Sets ID of the theme to be applied for this control. 
        /// </summary>
        [Browsable(true), DefaultValue(""), Category("Appearance"), Description("ID of the theme to be applied")]
        public string Theme
        {
            get { return mTheme; }
            set
            {
                mTheme = value;
                ApplyTheme(mTheme);
                Invalidate();
            }
        }
        #endregion

        #region Effective Theme
        private ITheme mEffectiveTheme;
        /// <summary>
        /// Gets the theme currently applied to this control.
        /// </summary>
        [Browsable(false)]
        public ITheme EffectiveTheme
        {
            get
            {
                //ensure the effective theme is not null
                if (mEffectiveTheme == null) mEffectiveTheme = UI.Themes.Current;
                #region Defensive tracing
                else
                {
                    //already has a theme
                }
                #endregion
                return mEffectiveTheme;
            }
        }
        #endregion

        #region Effective Renderer
        /// <summary>
        /// Gets the renderer that shall be responsible for rendering this control.
        /// </summary>
        [Browsable(false)]
        public IControlRenderer EffectiveRenderer
        {
            get
            {
                IControlRenderer result = null;
                if (mRenderer != null)
                {//has custom renderer
                    result = mRenderer;
                }
                else if (mThemeRenderer != null)
                {//has theme renderer
                    result = mThemeRenderer;
                }
                else
                {//no theme at all, try to use the default theme
                    mThemeRenderer = UI.Themes.Current.FindRenderer(GetType());
                    result = mThemeRenderer;
                }

                return result;
            }
        }
        #endregion

        #region Renderer
        /// <summary>
        /// The custom renderer set by user.
        /// </summary>
        private IControlRenderer mRenderer = null;
        /// <summary>
        /// Gets/Sets the renderer used for rendering this control.
        /// </summary>
        [Browsable(false), DefaultValue(null), Category("Appearance"), Description("The renderer used for rendering this control")]
        public IControlRenderer Renderer
        {
            get { return mRenderer; }
            set
            {
                mRenderer = value;
                Invalidate();
            }
        }
        #endregion

        #endregion

        #region On Get Render Context
        /// <summary>
        /// Get reference to the renderation context which is used by <see cref="IControlRenderer"/>.
        /// </summary>
        protected virtual RenderContext OnGetRenderContext(Graphics canvas)
        {
            return null;
        }
        #endregion

        #region Get Render Context
        /// <summary>
        /// Get reference to the renderation context which is used by <see cref="IControlRenderer"/>.
        /// </summary>
        RenderContext GetRenderContext(Graphics canvas)
        {
            RenderContext result = OnGetRenderContext(canvas);

            return result;
        }
        #endregion

        #region Drawing Routines

        #region On Render Content
        /// <summary>
        /// Paint the control's content (text, value, data, etc.) onto canvas.
        /// </summary>
        /// <param name="canvas">The canvas on which to paint the control.</param>
        /// <param name="renderer">The optional renderer for the selected theme.</param>
        /// <param name="context">The current drawing context.</param>
        protected virtual void OnRenderContent(Graphics canvas, IControlRenderer renderer, RenderContext context)
        {
            if (renderer != null)
            {
                renderer.RenderContent(this, canvas, context);
            }
            #region Defensive tracing
            else
            {
            }
            #endregion
        }
        #endregion

        #region On Render Visual
        /// <summary>
        /// Paint the control's visual stuff (border, background, etc.) onto canvas.
        /// </summary>
        /// <param name="canvas">The canvas on which to paint the control.</param>
        /// <param name="renderer">The optional renderer for the selected theme.</param>
        /// <param name="context">The current drawing context.</param>
        protected virtual void OnRenderVisual(Graphics canvas, IControlRenderer renderer, RenderContext context)
        {
            if (renderer != null)
            {
                renderer.RenderVisual(this, canvas, context);
            }
            #region Defensive tracing
            else
            {
                if (DesignMode)
                {
                    canvas.Clear(this.BackColor);
                    canvas.DrawString("ERROR: NO RENDERER FOUND!", Font, Brushes.Red, 5, 5);
                    Rectangle r = new Rectangle(5, 25, Width - 10, Height - 25);
                    StringFormat fmt = new StringFormat();
                    fmt.Trimming = StringTrimming.EllipsisCharacter;
                    canvas.DrawString("Descendants of ControlBase should either override OnRenderXXX or provide a renderer", Font, Brushes.Red, r, fmt);
                }
                #region Defensive tracing
                else
                {
                    //no need to warn at run-time
                }
                #endregion
            }
            #endregion
        }
        #endregion

        #region Draw Transparency
        /// <summary>
        /// Paint this control's parent to mimic the transparency effects.
        /// </summary>
        void DrawTransparency(Graphics canvas)
        {
            if (mCacheBackground)
            {
                //mRedrawBackground = true;
                if (mRedrawBackground)
                {
                    GetBackground(mBackgroundCanvas);

                    //suppress further drawing
                    mRedrawBackground = false;
                }
                #region Defensive tracing
                else
                {
                    //background is cached
                }
                #endregion

                canvas.DrawImageUnscaled(mBackgroundBitmap, 0, 0);
            }
            else
            {
                GetBackground(canvas);
            }
        }
        #endregion

        #region Draw Background
        /// <summary>
        /// Render the background.
        /// </summary>
        protected void DrawBackground(Graphics canvas)
        {
            if (BackgroundImage != null)
            {
                #region Has background image
                Rectangle r = new Rectangle(0, 0, Width, Height);
                DrawBackgroundImage(canvas, BackgroundImage, BackgroundImageLayout, r);
                #endregion
            }
            else
            {
                #region No background image -> fill with back color

                canvas.Clear(this.BackColor);

                //if (DesignMode)
                //{
                //    #region Design Mode
                //    //in design mode, the Parent of this control is not real

                //    canvas.Clear(this.BackColor);
                //    #endregion
                //}
                //else
                //{
                //    #region Runtime mode

                //    //fill in the background
                //    if (this.Parent != null)
                //    {
                //        canvas.Clear(this.Parent.BackColor);
                //    }
                //    else
                //    {
                //        canvas.Clear(this.BackColor);
                //    }

                //    #endregion
                //}

                #endregion
            }
        }
        #endregion

        #region Draw Background Image
        /// <summary>
        /// Render the background image on to the provided canvas.
        /// </summary>
        protected virtual void DrawBackgroundImage(Graphics canvas, Image img, ImageLayout layout, Rectangle r)
        {
            switch (layout)
            {
                #region Center
                case ImageLayout.Center:
                    r = new Rectangle(r.Left + r.Width / 2 - img.Width / 2, r.Top + r.Height / 2 - img.Height / 2, img.Width, img.Height);
                    canvas.DrawImageUnscaledAndClipped(img, r);
                    break;
                #endregion

                #region None
                case ImageLayout.None:
                    r = new Rectangle(0, 0, img.Width, img.Height);
                    //canvas.DrawImageUnscaled(img, 0, 0);
                    canvas.DrawImageUnscaledAndClipped(img, r);
                    break;
                #endregion

                #region Stretch
                case ImageLayout.Stretch:
                    canvas.DrawImage(img, r);
                    break;
                #endregion

                #region Tile
                case ImageLayout.Tile:
                    int x;
                    int y;
                    int x1 = r.Left;
                    int y1 = r.Top;
                    int x2 = r.Right;
                    int y2 = r.Bottom;
                    int w = img.Width;
                    int h = img.Height;

                    y = y1;
                    while (y < y2)
                    {
                        x = x1;
                        while (x < x2)
                        {
                            //draw current tile
                            canvas.DrawImage(img, x, y, w, h);

                            //next column
                            x += w;
                        }

                        //next row
                        y += h;
                    }
                    break;
                #endregion

                #region Zoom
                case ImageLayout.Zoom:

                    //calculate minimum size
                    int size = r.Width > r.Height ? r.Height : r.Width;

                    //render in the middle                    
                    r = new Rectangle(r.Left + r.Width / 2 - size / 2, r.Top + r.Height / 2 - size / 2, size, size);
                    canvas.DrawImage(img, r);
                    break;

                #endregion

                #region Unsupported
                default:
                    break;
                #endregion
            }
        }
        #endregion

        #region On Paint
        /// <summary>
        /// Paint this control. Descendants of this class should NOT override this method.
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            //Graphics g = null;

            #region Pre-conditions

            //immediately return, do not paint
            if ((mSkipPaint) || (Width < 1) || (Height < 1)) return;
            #region Defensive tracing
            else
            {
                //continue painting.
            }
            #endregion

            #endregion

            #region Perform layout
            if (mRecalculateLayout)
            {
                CalculateLayout();
            }
            #region Defensive tracing
            else
            {
                //layout calculation is not required, continue painting.
            }
            #endregion

            #endregion

            switch (mTransparencyMethod)
            {
                case TransparencyMethod.ForcedPainting:
                    OnPaintInForcedPainting(e);
                    break;
                case TransparencyMethod.TransparentWindows:

                    //only use transparent windows painting when transparent is set to
                    //true because this method draw directly to control's parent's graphics.
                    //It causes flickering.

                    if (mTransparent) OnPaintInTransparentWindows(e);
                    else OnPaintInForcedPainting(e);

                    break;
            }
        }
        #endregion

        #region On Paint In Forced Painting
        /// <summary>
        /// Paint this control when transparency method is Forced Painting.
        /// </summary>
        void OnPaintInForcedPainting(PaintEventArgs e)
        {
            #region Ensure buffers are setup
            if (mBufferPreparationRequired)
            {
                DisposeBuffers();
                PrepareBuffers();

                //suppress further allocation
                mBufferPreparationRequired = false;
            }
            #region Defensive tracing
            else
            {
                //no need to re-create buffers.
            }
            #endregion

            #endregion

            Graphics g = mControlCanvas;
            g.ResetTransform();

            #region Render to buffer
            if (mRenderRequired)
            {
                #region Render background

                if (mTransparent)
                {
                    DrawTransparency(g);
                }
                else
                {
                    DrawBackground(g);
                }

                #endregion

                #region Apply renderation quality
                switch (mQuality)
                {
                    case RenderQuality.Quality:
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.TranslateTransform(0.5f, 0.5f);//fix the anoying pen.width = 1 bug
                        break;

                    case RenderQuality.Normal:
                        g.SmoothingMode = SmoothingMode.AntiAlias;
                        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        g.CompositingQuality = CompositingQuality.Default;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                        g.TranslateTransform(0.5f, 0.5f);//fix the anoying pen.width = 1 bug
                        break;

                    case RenderQuality.Speed:
                        g.SmoothingMode = SmoothingMode.HighSpeed;
                        g.PixelOffsetMode = PixelOffsetMode.Default;
                        g.CompositingQuality = CompositingQuality.HighSpeed;
                        g.TextRenderingHint = TextRenderingHint.SystemDefault;
                        break;

                    default:
                        break;
                }
                #endregion

                #region Obtain renderer
                IControlRenderer renderer = EffectiveRenderer;
                #endregion

                //create context
                RenderContext context = GetRenderContext(g);

                //render
                OnRenderVisual(g, renderer, context);
                OnRenderContent(g, renderer, context);

                //suppress further render
                mRenderRequired = false;
            }
            else
            {
                //render is not required
            }

            #endregion

            #region Blast to screen

            //render the control buffer
            e.Graphics.DrawImageUnscaled(mControlBitmap, 0, 0);

            #endregion

        }

        public Rectangle ConvertToScreen(Rectangle r)
        {
            return ToScreen(this, r);
        }
        #endregion

        #region On Paint In Transparent Windows
        /// <summary>
        /// Paint this control when transparency method is Transparent Windows.
        /// </summary>
        void OnPaintInTransparentWindows(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.ResetTransform();

            #region Render graphics

            #region Apply renderation quality
            switch (mQuality)
            {
                case RenderQuality.Quality:
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                    g.TranslateTransform(0.5f, 0.5f);//fix the anoying pen.width = 1 bug
                    break;

                case RenderQuality.Normal:
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    g.CompositingQuality = CompositingQuality.Default;
                    g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                    g.TranslateTransform(0.5f, 0.5f);//fix the anoying pen.width = 1 bug
                    break;

                case RenderQuality.Speed:
                    g.SmoothingMode = SmoothingMode.HighSpeed;
                    g.PixelOffsetMode = PixelOffsetMode.Default;
                    g.CompositingQuality = CompositingQuality.HighSpeed;
                    g.TextRenderingHint = TextRenderingHint.SystemDefault;
                    break;

                default:
                    break;
            }
            #endregion

            #region Render background
            if (mTransparent)
            {
                //Let windows handle the background
            }
            else
            {
                DrawBackground(g);
            }

            #endregion

            //obtain renderer
            IControlRenderer renderer = EffectiveRenderer;

            //create context
            RenderContext context = GetRenderContext(g);

            //render
            OnRenderVisual(g, renderer, context);
            OnRenderContent(g, renderer, context);

            #endregion
        }
        #endregion

        #region On Paint Background
        /// <summary>
        /// Paint this control's background.
        /// </summary>
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            Graphics canvas = pevent.Graphics;

            if (mTransparent)
            {//transparent mode

                #region Transparent Mode

                if (mTransparencyMethod == TransparencyMethod.TransparentWindows)
                {
                    //let base class handle it
                    base.OnPaintBackground(pevent);
                }
                else
                {
                    //no need to do anything when using ForcedPainting method.
                }

                #endregion
            }
            #region Defensive tracing
            else
            {
                //do nothing to prevent flickering
            }
            #endregion
        }
        #endregion

        #region Get Background
        Rectangle rSelf;

        /// <summary>
        /// Capture the background of this control by invalidating underlying controls
        /// </summary>
        void GetBackground(Graphics canvas)
        {
            //if (this.Parent != null)
            //{
            //    Rectangle r = new Rectangle(Left, Top, Width, Height);
            //    GraphicsState state = canvas.Save();
            //    //canvas.SetClip(r);
            //    RenderControl(this.Parent, canvas, r, true);
            //    canvas.Restore(state);
            //}
            //#region Defensive tracing
            //else
            //{

            //}
            //#endregion

            #region Old Codes

            mSkipPaint = true;

            bool slowCapture = true;

            if (Parent is IBufferProvider)
            {
                IBufferProvider bp = (IBufferProvider)Parent;
                if (bp.HasBuffer)
                {
                    Bitmap buffer = bp.Background;
                    if (buffer != null)
                    {
                        slowCapture = false;
                        Rectangle rDest = new Rectangle(0, 0, Width, Height);
                        Rectangle rSrc = new Rectangle(Left, Top, Width, Height);
                        canvas.DrawImage(buffer, rDest, rSrc, GraphicsUnit.Pixel);
                    }
                }
            }

            if (slowCapture)
            {
                //invoke parent's OnPaint
                Control con = Parent;
                if (con != null)
                {
                    int dx = -Left;
                    int dy = -Top;
                    rSelf = new Rectangle(Left, Top, Width, Height);
                    Rectangle rIntersect = con.ClientRectangle;
                    rIntersect.Intersect(rSelf);

                    DrawControl(con, canvas, ToScreen(con, rIntersect));
                }
            }

            //return result
            mSkipPaint = false;

            #endregion
        }

        #region ToScreen / FromScreen
        Rectangle ToScreen(Control con, Rectangle r)
        {
            return new Rectangle(con.PointToScreen(r.Location), r.Size);
        }

        Rectangle ToClient(Control con, Rectangle r)
        {
            return new Rectangle(con.PointToClient(r.Location), r.Size);
        }
        #endregion

        #region Draw Control
        void DrawControl(Control con, Graphics canvas, Rectangle clipRect)
        {
            //if (con != this)
            //{
            //    if (con is IControl)
            //    {
            //        #region IControl case
            //        IControl ic = (IControl)con;

            //        //save current state
            //        GraphicsState state = canvas.Save();

            //        //translate to the control's position
            //        canvas.TranslateTransform(con.Left, con.Top);

            //        //render it
            //        ic.Render(canvas, clipRect, true);

            //        //draw children on buffer
            //        if (con.Controls.Count > 0) DrawControlChildren(con, canvas, clipRect);

            //        //restore state
            //        canvas.Restore(state);

            //        #endregion
            //    }
            //    else
            //    {
            //        #region Normal case
            //        #endregion
            //    }
            //}
            //#region Defensive tracing
            //else
            //{
            //    //no need to draw myself.
            //}
            //#endregion

            #region Old codes

            if ((con != this) && (con.Visible))
            {
                //create a buffer bitmap to draw onto
                Bitmap bmp = new Bitmap(con.Width, con.Height, PixelFormat.Format32bppPArgb);
                Graphics g = Graphics.FromImage(bmp);
                PaintEventArgs pea = null;
                Rectangle clientClipRect = ToClient(con, clipRect);
                pea = new PaintEventArgs(g, clientClipRect);
                g.SetClip(clientClipRect);

                //draw control on buffer

                if (con is IControl)
                {
                    IControl ic = (IControl)con;
                    ic.Render(g, clientClipRect, true);
                }
                else
                {
                    InvokePaintBackground(con, pea);
                    InvokePaint(con, pea);
                }

                //draw children on buffer
                if (con.Controls.Count > 0) DrawControlChildren(con, g, clipRect);

                //blast to my canvas
                Rectangle rSource = clientClipRect;
                Rectangle rDest = ToClient(this, clipRect);
                if (con != this.Parent) rDest = ToClient(con.Parent, clipRect);
                canvas.DrawImage(bmp, rDest, rSource.Left, rSource.Top, rSource.Width, rSource.Height, GraphicsUnit.Pixel);

                //dipose stuff
                g.Dispose();
                g = null;
                bmp.Dispose();
                bmp = null;
                pea.Dispose();
                pea = null;
            }

            #endregion
        }
        #endregion

        #region Draw Control Children
        void DrawControlChildren(Control con, Graphics canvas, Rectangle clipRect)
        {
            for (int i = con.Controls.Count - 1; i >= 0; i--)
            {
                Control child = con.Controls[i];
                if ((con != this) && (child != this))
                {
                    Rectangle rIntersect = ToScreen(con, new Rectangle(child.Left, child.Top, child.Width, child.Height));
                    rIntersect.Intersect(clipRect);
                    if (!rIntersect.IsEmpty)
                    {
                        DrawControl(child, canvas, rIntersect);
                    }
                }
                else break;
            }
        }
        #endregion

        #region Render Control
        /// <summary>
        /// Render a specific control onto the provided canvas.
        /// </summary>
        /// <param name="con">The control to be rendered.</param>
        /// <param name="canvas">The painting canvas to render to.</param>
        /// <param name="clip">The clipping area.</param>
        /// <param name="includeChildren">Whether children control that intersects with the clipping area shall be rendered as well.</param>
        void RenderControl(Control con, Graphics canvas, Rectangle clip, bool includeChildren)
        {
            //ask parent to render
            if (con.Parent != null)
            {
                //Rectangle r = new Rectangle(Left, Top, Width, Height);
                //GraphicsState state = canvas.Save();
                //canvas.SetClip(r);
                //RenderControl(con.Parent, canvas, r, includeChildren);
                //canvas.Restore(state);
            }
            #region Defensive tracing
            else
            {
                //no parent left
            }
            #endregion

            if (con is IControl)
            {
                #region Well-known IControl case

                //request the control to paint itself on our canvas
                IControl ic = (IControl)con;
                ic.Render(canvas, clip, false);

                #endregion
            }
            else
            {
                #region General control

                string msg = string.Format("Cannot render {0}", con.Name);
                canvas.DrawString(msg, Font, Brushes.Red, clip.X, clip.Y);

                #endregion
            }

            canvas.DrawString(con.Name, Font, Brushes.Blue, clip.Left, clip.Top + 10);
            Log.Debug("RenderControl - {0} - clip: {1}", con.Name, clip);
        }
        #endregion

        #endregion

        #region Invalidate Background
        /// <summary>
        /// Request new renderation, ensure that background is refreshed. This is necessary
        /// when in transparent mode is TransparentWindows and the area of painting is changed.
        /// </summary>
        public void InvalidateBackground()
        {
            try
            {
                mRenderRequired = true;
                if (InvokeRequired) Invoke(mInvalidateBackgroundHandler, this, EventArgs.Empty);
                else DoInvalidateBackground(null, null);
            }
            catch
            {
                //deliberately ignore any errors that might occur
            }
        }
        /// <summary>
        /// Event handler for InvalidateBackground
        /// </summary>
        EventHandler mInvalidateBackgroundHandler = null;

        void DoInvalidateBackground(object sender, EventArgs e)
        {
            if (mTransparencyMethod == TransparencyMethod.ForcedPainting)
            {
                mRedrawBackground = true;
                mRenderRequired = true;
                Invalidate();
            }
            else
            {
                if (this.Parent != null) Parent.Invalidate(this.Bounds, true);
                #region Defensive tracing
                else
                {
                    //no parent to invalidate against
                }
                #endregion
            }
        }
        #endregion

        #region Invalidate Renderation
        /// <summary>
        /// Mark the visual to be rendered and invalidate control.
        /// </summary>
        public void InvalidateRenderation()
        {
            mRenderRequired = true;
            Invalidate();
        }
        #endregion

        #region Invalidate - Threadsafe version
        /// <summary>
        /// Event handler for Invalidate.
        /// </summary>
        EventHandler mInvalidateHandler = null;

        void DoInvalidate(object sender, EventArgs e)
        {
            base.Invalidate();
        }

        /// <summary>
        /// A thread-safe version of invalidate.
        /// </summary>
        public new void Invalidate()
        {
            try
            {
                mRenderRequired = true;
                if (InvokeRequired) Invoke(mInvalidateHandler, this, EventArgs.Empty);
                else DoInvalidate(null, null);
            }
            catch
            {
                //deliberately ignore any errors that might occur
            }
        }
        #endregion

        #endregion

        #region Theming
        /// <summary>
        /// The renderer for this control based on current theme settings.
        /// </summary>
        private IControlRenderer mThemeRenderer = null;

        #region Apply Theme
        void ApplyTheme(string themeId)
        {
            //find renderer based on theme ID
            if ((themeId != null) && (themeId != ""))
            {
                if (UI.Themes.Contains(themeId))
                {
                    mEffectiveTheme = UI.Themes[themeId];
                    mThemeRenderer = mEffectiveTheme.FindRenderer(GetType());
                }
                else
                {
                    mEffectiveTheme = UI.Themes.Current;
                    mThemeRenderer = null;
                }
            }
            else
            {
                mEffectiveTheme = UI.Themes.Current;
                mThemeRenderer = mEffectiveTheme.FindRenderer(GetType());
            }
        }
        #endregion

        #endregion

        #region Layout

        #region Invalidate Layout
        /// <summary>
        /// Marks the layout as to be recalculated and invalidate control.
        /// </summary>
        public void InvalidateLayout()
        {
            mRecalculateLayout = true;
            Invalidate();
        }
        #endregion

        #region On Calculate Layout
        /// <summary>
        /// Perform layout calculations neccessary for this control.
        /// </summary>
        protected virtual void OnCalculateLayout()
        {
        }
        #endregion

        #region Calculate Layout
        /// <summary>
        /// Perform layout calculations neccessary for this control.
        /// </summary>
        private void CalculateLayout()
        {
            OnCalculateLayout();
            mRecalculateLayout = false;
        }
        #endregion

        #endregion

        #region Double - Buffering
        /// <summary>
        /// The bitmap that stores this control's painting.
        /// </summary>
        Bitmap mControlBitmap = null;
        /// <summary>
        /// The bitmap that stores this control's parent painting in the area occupied by this control.
        /// </summary>
        Bitmap mBackgroundBitmap = null;
        /// <summary>
        /// Graphics association for mControlBitmap.
        /// </summary>
        Graphics mControlCanvas = null;
        /// <summary>
        /// Graphics association for mBackgroundBitmap.
        /// </summary>
        Graphics mBackgroundCanvas = null;
        /// <summary>
        /// Whether buffers should be recreated.
        /// </summary>
        bool mBufferPreparationRequired = true;

        #region Prepare Buffers
        /// <summary>
        /// Recreate buffer bitmaps
        /// </summary>
        void PrepareBuffers()
        {
            int w = Width;
            int h = Height;

            if (mCacheBackground)
            {
                //mBackgroundBitmap = new Bitmap(w, h, PixelFormat.Format32bppPArgb);
                mBackgroundBitmap = new Bitmap(w, h, PixelFormat.Format32bppArgb);
                mBackgroundCanvas = Graphics.FromImage(mBackgroundBitmap);
            }
            #region Defensive tracing
            else
            {
                //background caching is not required
            }
            #endregion

            //mControlBitmap = new Bitmap(w, h, PixelFormat.Format32bppPArgb);
            mControlBitmap = new Bitmap(w, h, PixelFormat.Format32bppArgb);
            mControlCanvas = Graphics.FromImage(mControlBitmap);
        }
        #endregion

        #region Dispose Buffers
        void DisposeBuffers()
        {
            if (mBackgroundCanvas != null)
            {
                mBackgroundCanvas.Dispose();
                mBackgroundCanvas = null;
            }
            #region Defensive tracing
            else
            {
                //null, no need to dispose
            }
            #endregion

            if (mBackgroundBitmap != null)
            {
                mBackgroundBitmap.Dispose();
                mBackgroundBitmap = null;
            }
            #region Defensive tracing
            else
            {
                //null, no need to dispose
            }
            #endregion

            if (mControlCanvas != null)
            {
                mControlCanvas.Dispose();
                mControlCanvas = null;
            }
            #region Defensive tracing
            else
            {
                //null, no need to dispose
            }
            #endregion

            if (mControlBitmap != null)
            {
                mControlBitmap.Dispose();
                mControlBitmap = null;
            }
            #region Defensive tracing
            else
            {
                //null, no need to dispose
            }
            #endregion
        }
        #endregion

        #endregion

        #region On Resize
        /// <summary>
        /// This method is raised when the control's sizes are changed.
        /// </summary>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            mBufferPreparationRequired = true;
            mRedrawBackground = true;
            mRecalculateLayout = true;
            Invalidate();
        }
        #endregion

        #region On Move
        /// <summary>
        /// This method is raised when the control's positions are changed.
        /// </summary>
        protected override void OnMove(EventArgs e)
        {
            base.OnMove(e);
            mRedrawBackground = true;
            Invalidate();
        }
        #endregion

        #region Events override for proper invalidation

        #region On Fore Color Changed
        protected override void OnForeColorChanged(EventArgs e)
        {
            base.OnForeColorChanged(e);
            Invalidate();
        }
        #endregion

        #region On Back Color Changed
        protected override void OnBackColorChanged(EventArgs e)
        {
            base.OnBackColorChanged(e);
            Invalidate();
        }
        #endregion

        #region On Got Focus
        protected override void OnGotFocus(EventArgs e)
        {
            Invalidate();
        }
        #endregion

        #region On Lost Focus
        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            Invalidate();
        }
        #endregion

        #region On Font Changed
        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            Invalidate();
        }
        #endregion

        #region On Parent Changed
        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);

            //detach from current parent
            if (mCurrentParent != null) DetachFromParent(mCurrentParent);
            #region Defensive tracing
            else
            {
                //no previous parent
            }
            #endregion

            base.OnParentChanged(e);

            //attach to new parent
            mCurrentParent = this.Parent;
            if (mCurrentParent != null) AttachToParent(mCurrentParent);
            #region Defensive tracing
            else
            {
                //no parent
            }
            #endregion
        }
        #endregion

        #region On Padding Changed
        protected override void OnPaddingChanged(EventArgs e)
        {
            base.OnPaddingChanged(e);
            InvalidateLayout();
        }
        #endregion

        #region On Margin Changed
        protected override void OnMarginChanged(EventArgs e)
        {
            base.OnMarginChanged(e);
            InvalidateLayout();
        }
        #endregion

        #region On Visible Changed
        protected override void OnVisibleChanged(EventArgs e)
        {
            //mRedrawBackground = true;
            //base.OnVisibleChanged(e);
            Invalidate();
        }
        #endregion

        #region On Background Image Changed
        protected override void OnBackgroundImageChanged(EventArgs e)
        {
            base.OnBackgroundImageChanged(e);
            InvalidateBackground();
        }
        #endregion

        #region On Background Image Layout Changed
        protected override void OnBackgroundImageLayoutChanged(EventArgs e)
        {
            base.OnBackgroundImageLayoutChanged(e);
            InvalidateBackground();
        }
        #endregion

        #region On Enabled Changed
        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);
            Invalidate();
        }
        #endregion

        #endregion

        #region Parent's events handling
        Control mCurrentParent = null;

        #region Attach To Parent
        void AttachToParent(Control parent)
        {
            parent.SizeChanged += new EventHandler(parent_SizeChanged);
        }
        #endregion

        #region Detach From Parent
        void DetachFromParent(Control parent)
        {
            parent.SizeChanged -= new EventHandler(parent_SizeChanged);
        }
        #endregion

        #region Parent Size Changed
        void parent_SizeChanged(object sender, EventArgs e)
        {
            //properly invalidate background
            if (mTransparent && mTransparencyMethod == TransparencyMethod.ForcedPainting)
            {
                InvalidateBackground();
            }
            #region Defensive tracing
            else
            {
                //no need to redraw
            }
            #endregion
        }
        #endregion

        #endregion

        #region Set Default Styles
        /// <summary>
        /// Setting up default styles using SetStyle()
        /// </summary>
        protected void SetDefaultStyles()
        {
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            //this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.UserPaint, true);

            //for transparent windows
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.Opaque, true);
            //this.BackColor = Color.Transparent;
        }
        #endregion

        #region Create Params
        /// <summary>
        /// Override create params to support transparency.
        /// </summary>
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams createParams = base.CreateParams;

                if (mTransparent && mTransparencyMethod == TransparencyMethod.TransparentWindows)
                {
                    createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
                }
                #region Defensive tracing
                else
                {

                }
                #endregion

                return createParams;
            }
        }
        #endregion

        #region Dispose
        /// <summary>
        /// Clean up resources.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            DisposeBuffers();
            base.Dispose(disposing);
        }
        #endregion

        #region IControl Members

        #region Render
        /// <summary>
        /// Render this control on the provided graphics canvas.
        /// </summary>
        /// <param name="canvas">The canvas to render on to.</param>
        /// <param name="clip">The portion of the control to be rendered.</param>
        /// <param name="includeBackground">Whether the background shall be painted as well when transparent is false.</param>
        public void Render(Graphics canvas, Rectangle clip, bool includeBackground)
        {
            #region Pre-conditions

            //immediately return, do not paint
            if ((mSkipPaint) || (Width < 1) || (Height < 1)) return;
            #region Defensive tracing
            else
            {
                //continue painting.
            }
            #endregion

            #endregion

            #region Ensure buffers are setup
            if (mBufferPreparationRequired)
            {
                DisposeBuffers();
                PrepareBuffers();
                CalculateLayout();

                //suppress further allocation
                mBufferPreparationRequired = false;
            }
            #region Defensive tracing
            else
            {
                //no need to re-create buffers.
            }
            #endregion

            #endregion

            Graphics g = canvas;
            GraphicsState state = g.Save();
            //g.SetClip(clip);
            //GetBackground(canvas);

            #region Render background

            if (includeBackground)
            {
                if (mTransparent)
                {
                    DrawTransparency(g);
                }
                else
                {
                    DrawBackground(g);
                }
            }
            #region Defensive tracing
            else
            {
                //not required
            }
            #endregion

            #endregion

            #region Apply renderation quality
            switch (mQuality)
            {
                case RenderQuality.Quality:
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                    g.TranslateTransform(0.5f, 0.5f);//fix the anoying pen.width = 1 bug
                    break;

                case RenderQuality.Normal:
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    g.CompositingQuality = CompositingQuality.Default;
                    g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                    g.TranslateTransform(0.5f, 0.5f);//fix the anoying pen.width = 1 bug
                    break;

                case RenderQuality.Speed:
                    g.SmoothingMode = SmoothingMode.HighSpeed;
                    g.PixelOffsetMode = PixelOffsetMode.Default;
                    g.CompositingQuality = CompositingQuality.HighSpeed;
                    g.TextRenderingHint = TextRenderingHint.SystemDefault;
                    break;

                default:
                    break;
            }
            #endregion

            #region Obtain renderer
            IControlRenderer renderer = EffectiveRenderer;
            #endregion

            //create context
            RenderContext context = GetRenderContext(g);

            //render
            OnRenderVisual(g, renderer, context);
            OnRenderContent(g, renderer, context);

            //restore state
            g.Restore(state);

            //debug cues
            //Color c = Color.FromArgb(ran.Next(255), ran.Next(255), ran.Next(255));
            //Brush b = new SolidBrush(c);
            //g.FillRectangle(b, 0, 0, 10, 10);
            //b.Dispose();
        }

        //Random ran = new Random();
        #endregion

        #endregion

        #region ISupportTransparency Members

        #region Invalidate Transparency
        /// <summary>
        /// Signify that this controls should invalidate its background for transparency consistent.
        /// </summary>
        void ISupportTransparency.InvalidateTransparency()
        {
            mRedrawBackground = true;
            InvalidateChildrenTransparency(this);
        }

        void InvalidateChildrenTransparency(Control con)
        {
            foreach (Control child in con.Controls)
            {
                if (child is ISupportTransparency) ((ISupportTransparency)child).InvalidateTransparency();
                else InvalidateChildrenTransparency(child);
            }
        }
        #endregion

        #endregion

        #region IMouseListener Members

        #region Notify Mouse Enter
        /// <summary>
        /// Command the listener to handle Mouse Enter event logic.
        /// </summary>
        void IMouseListener.NotifyMouseEnter()
        {
            OnMouseEnter(EventArgs.Empty);
        }
        #endregion

        #region Notify Mouse Leave
        /// <summary>
        /// Command the listener to handle Mouse Leave event logic.
        /// </summary>
        void IMouseListener.NotifyMouseLeave()
        {
            OnMouseLeave(EventArgs.Empty);
        }
        #endregion

        #region Notify Mouse Up
        /// <summary>
        /// Command the listener to handle Mouse Up event logic.
        /// </summary>
        void IMouseListener.NotifyMouseUp(MouseEventArgs e)
        {
            OnMouseUp(e);
        }
        #endregion

        #region Notify Mouse Down
        /// <summary>
        /// Command the listener to handle Mouse Down event logic.
        /// </summary>
        void IMouseListener.NotifyMouseDown(MouseEventArgs e)
        {
            OnMouseDown(e);
        }
        #endregion

        #region Notify Mouse Move
        /// <summary>
        /// Command the listener to handle Mouse Move event logic.
        /// </summary>
        void IMouseListener.NotifyMouseMove(MouseEventArgs e)
        {
            OnMouseMove(e);
        }
        #endregion

        #region Notify Mouse Wheel
        /// <summary>
        /// Command the listener to handle Mouse Wheel event logic.
        /// </summary>
        void IMouseListener.NotifyMouseWheel(MouseEventArgs e)
        {
            OnMouseWheel(e);
        }
        #endregion

        #region Notify Mouse Click
        /// <summary>
        /// Command the listener to handle Mouse Click event logic.
        /// </summary>
        void IMouseListener.NotifyMouseClick(MouseEventArgs e)
        {
            OnMouseClick(e);
        }
        #endregion

        #region Notify Mouse Double Click
        /// <summary>
        /// Command the listener to handle Mouse Double Click event logic.
        /// </summary>
        void IMouseListener.NotifyMouseDoubleClick(MouseEventArgs e)
        {
            OnMouseDoubleClick(e);
        }
        #endregion

        #region Notify Click
        /// <summary>
        /// Command the listener to handle Click event logic.
        /// </summary>
        void IMouseListener.NotifyClick()
        {
            OnClick(EventArgs.Empty);
        }
        #endregion

        #region Notify Double Click
        /// <summary>
        /// Command the listener to handle Double Click event logic.
        /// </summary>
        void IMouseListener.NotifyDoubleClick()
        {
            OnDoubleClick(EventArgs.Empty);
        }
        #endregion

        #endregion

        #region IKeyboardListener Members

        #region Notify Key Up
        /// <summary>
        /// Command the listener to handle Key Up event logic.
        /// </summary>
        void IKeyboardListener.NotifyKeyUp(KeyEventArgs e)
        {
            OnKeyUp(e);
        }
        #endregion

        #region Notify Key Down
        /// <summary>
        /// Command the listener to handle Key Down event logic.
        /// </summary>
        void IKeyboardListener.NotifyKeyDown(KeyEventArgs e)
        {
            OnKeyDown(e);
        }
        #endregion

        #region Notify Key Press
        /// <summary>
        /// Command the listener to handle Key Press event logic.
        /// </summary>
        void IKeyboardListener.NotifyKeyPress(KeyPressEventArgs e)
        {
            OnKeyPress(e);
        }
        #endregion

        #endregion

        #region Constructors
        /// <summary>
        /// Create a new instance.
        /// </summary>
        public ControlBase()
        {
            mDesignMode = LicenseManager.UsageMode == LicenseUsageMode.Designtime;
            mInvalidateHandler = new EventHandler(DoInvalidate);
            mInvalidateBackgroundHandler = new EventHandler(DoInvalidateBackground);
            SetDefaultStyles();
        }
        #endregion
    }
}